package mysql

import (
	"context"
	"gorm.io/gorm"
	"inspector/internal/enums"
	"inspector/internal/model/entity"
	"inspector/pkg/code"
	"inspector/pkg/errors"
)

type Event struct {
	db *gorm.DB
}

func newEvent(tx *gorm.DB) *Event {
	return &Event{
		db: tx,
	}
}

// Create creates the event.
func (d *Event) Create(ctx context.Context, event *entity.Event) (res *entity.Event, err error) {
	result := d.db.WithContext(ctx).Create(event)
	if result.Error != nil {
		return nil, result.Error
	}
	return event, nil
}

// Update updates the event.
func (d *Event) Update(ctx context.Context, event *entity.Event) error {
	result := d.db.WithContext(ctx).Save(event)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

// Delete deletes the event by instance id.
func (d *Event) Delete(ctx context.Context, instanceID string) error {
	result := d.db.WithContext(ctx).Delete(&entity.Event{}, "instance_id = ?", instanceID)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return errors.New(code.NewErrDBQueryFailed(), "no event found with the specified instanceID")
	}
	return nil
}

// Get gets the event by instance id.
func (d *Event) Get(ctx context.Context, instanceID string) (*entity.Event, error) {
	var event entity.Event
	result := d.db.WithContext(ctx).First(&event, "instance_id = ?", instanceID)
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, result.Error
	}
	return &event, nil
}

// List lists the events.
func (d *Event) List(ctx context.Context, options entity.EventListOptions) ([]*entity.Event, error) {
	var events []*entity.Event
	tx := d.db.WithContext(ctx).Table("app_event")
	if options.EventType != "" {
		tx = tx.Where("event_type = ?", options.EventType)
	}
	if options.EventStatus != enums.EVENT_UNKNOWN {
		tx = tx.Where("event_status = ?", options.EventStatus)
	}
	if options.RetryCount != 0 {
		tx = tx.Where("retry_count = ?", options.RetryCount)
	}
	err := tx.Find(&events).Error
	if err != nil {
		return nil, err
	}
	return events, nil
}

// ListRetryEvents lists the retry events.
func (d *Event) ListRetryEvents(ctx context.Context, options entity.EventListOptions) ([]*entity.Event, error) {
	var events []*entity.Event
	tx := d.db.WithContext(ctx).Table("app_event")
	if options.EventType != "" {
		tx = tx.Where("event_type = ?", options.EventType)
	}
	if options.EventStatus != enums.EVENT_UNKNOWN {
		tx = tx.Where("event_status = ?", options.EventStatus)
	}
	if options.RetryCount != 0 {
		tx = tx.Where("retry_count < ?", options.RetryCount)
	}
	err := tx.Find(&events).Error
	if err != nil {
		return nil, err
	}
	return events, nil
}
